#include "tetris.h"
#include "ui_tetris.h"
#include <QPainter>
#include <QDateTime>
#include <QMessageBox>
#include "o.h"
#include "i.h"
#include "t.h"
#include "j.h"
#include "l.h"
#include "z.h"
#include "s.h"


Tetris::Tetris(QWidget *parent)
    : QWidget(parent)
    , ui(new Ui::Tetris)
{
    ui->setupUi(this);
    bg .load(":/pic/tetris.png");
    Iimg .load(":/pic/I.png");
    Jimg .load(":/pic/J.png");
    Limg .load(":/pic/L.png");
    Oimg .load(":/pic/O.png");
    Timg .load(":/pic/T.png");
    Simg .load(":/pic/S.png");
    Zimg .load(":/pic/Z.png");
    this->resize(bg.width(),bg.height());
    qsrand(QDateTime::currentDateTime().toTime_t());
    init();
}

Tetris::~Tetris()
{
    delete ui;
}

void Tetris::init(){
    curr = NULL;
    next = NULL;
    store = NULL;
    temp = NULL;
    newnext();
    for (int i=0;i<20;i++) {
        for (int j=0;j<10;j++) {
            wall[i][j] = NULL;
        }
    }
    score = 0;
    level = 1;
    tval = 1000;
    status = 0;
    tid = this->startTimer(tval);
    update();
}

bool Tetris::inwall(){
    for (int i=0;i<4;i++) {
        if (curr->cells[i]->row >= 0) {
            return true;
        }
    }return false;
}


void Tetris::newnext(){
    if(next == NULL){
        randnext();
    }
    curr = next;
    while (inwall()) {
        curr->up();
    }
    randnext();
}


void Tetris::changestore(){
        if(store == NULL){
            temp = curr;
            int x,y;
            x = curr->cells[1]->row - 0;
            y = curr->cells[1]->col - 4;
            for(int i=0;i<4;i++){
                temp->cells[i]->row -= x;
                temp->cells[i]->col -= y;
            }
            store = temp;
            curr = next;
            newnext();
        }else{
            temp = store;
            store = curr;
            int x,y;
            x = curr->cells[1]->row - 0;
            y = curr->cells[1]->col - 4;
            for(int i=0;i<4;i++){
                store->cells[i]->row -= x;
                store->cells[i]->col -= y;
            }
            curr = temp;
        }update();
}



void Tetris::randnext(){
    int n = qrand()%7;
    switch(n)
    {
    case 0:
            next = new I(Iimg);
            break;
    case 1:
            next = new O(Oimg);
            break;
    case 2:
            next = new J(Jimg);
            break;
    case 3:
            next = new L(Limg);
            break;
    case 4:
            next = new Z(Zimg);
            break;
    case 5:
            next = new S(Simg);
            break;
    case 6:
            next = new T(Timg);
            break;
    }
    int m = qrand()%4;
    for (int i=0;i<=m;i++) {
        next->rotate(1);
    }
}


void Tetris::drawBack(QPainter &p){
    for (int i=0;i<20;i++) {
        for (int j=0;j<10;j++) {
            if(wall[i][j] != NULL){
                p.drawImage(j*26,i*26,wall[i][j]->img);
            }
        }
    }

}

void Tetris::drawCurr(QPainter &p){
    if (curr == NULL){
        return ;
    }
    for(int i=0;i<4;i++){
        if(curr->cells[i]->row>=0){
            p.drawImage(curr->cells[i]->col*26,
                    curr->cells[i]->row*26,
                    curr->cells[i]->img);
        }
    }
}

void Tetris::drawNext(QPainter &p){
    if (next == NULL){
        return ;
    }
    for(int i=0;i<4;i++){
        p.drawImage((next->cells[i]->col + 7.9)*26,
                (next->cells[i]->row + 1)*26,
                next->cells[i]->img);
    }
}



void Tetris::drawStore(QPainter &p){
    if (store == NULL){
        return ;
    }
    for(int i=0;i<4;i++){
        p.drawImage((store->cells[i]->col + 12)*26,
                (store->cells[i]->row + 1)*26,
                store->cells[i]->img);
    }
}



void Tetris::drawlines(QPainter &p){
    for(int i=0;i<=10;i++){
        p.drawLine(i*26,0,i*26,20*26);
    }
    for(int i=0;i<=20;i++){
        p.drawLine(0,i*26,10*26,i*26);
    }
}

void Tetris::drawScore(QPainter &p){
    p.drawText(320,155,"SCORE:"+QString().setNum(score));
    p.drawText(320,214,"LEVEL:"+QString().setNum(level));
    p.drawText(283,235,"[C]Continue [R]Restart");
    p.drawText(283,285,"[S]Store");
}

void Tetris::paintEvent(QPaintEvent *event){
    QPainter p(this);
    p.drawImage(0,0,bg);
    p.translate(15,15);
    drawlines(p);
    drawCurr(p);
    drawNext(p);
    drawStore(p);
    drawBack(p);
    drawScore(p);
}


void Tetris::timerEvent(QTimerEvent *event){
    down();
    update();

}


void Tetris::keyPressEvent(QKeyEvent *event){
    int key = event->key();
    if(status == 0){
        if(key == Qt::Key_Left){
            if(canleft()){
                curr->left();
            }
        }if(key == Qt::Key_Right){
            if(canright()){
                curr->right();
            }
        }if(key == Qt::Key_Up){
            rotate();
        }if(key == Qt::Key_Down){
            down();
        }if(key == Qt::Key_Space){
            while (candown()) {
                down();
            }
        }
    }if(key == Qt::Key_R){
        killTimer(tid);
        init();
    }if(key == Qt::Key_Q){
        close();
    }if(key == Qt::Key_P){
        if(status == 0){
            this->killTimer(tid);
            status = 1;
        }
    }if(key == Qt::Key_C){
        if(status == 1){
            tid = this->startTimer(tval);
            status = 0;
        }
    }
    if(key == Qt::Key_S){
        changestore();
    }

    update();

}


void Tetris::landdown(){
    for(int i=0;i<4;i++){
        wall[curr->cells[i]->row][curr->cells[i]->col] = curr->cells[i];
    }

}

bool Tetris::fullline(int line){
    for (int i=0;i<10;i++) {
        if(wall[line][i] == NULL){
            return false;
        }
    }return true;
}

void Tetris::putdownline(int line){
    for(int i=0;i<10;i++){
        if(wall[line][i] != NULL){
            delete wall[line][i];
        }
    }
    for (int i=line;i>0;--i) {
            for (int j=0;j<10;j++) {
                wall[i][j] = wall[i-1][j];
            }
        }
        for (int j=0;j<10;j++) {
            wall[0][j] = NULL;
        }
}


void Tetris::clearline(){
    int num = 0;
    for(int line=19;line>=0;--line){
                if(fullline(line)){
                    putdownline(line);
                    ++line;
                    ++num;
                }
        }
    if(num == 1){
        score += 10;
    }else if(num == 2){
        score += 30;
    }else if(num == 3){
        score += 50;
    }else if(num == 4){
        score += 70;
    }

    if(score/100 == level){
        ++level;
        this->killTimer(tid);
        tval -= 150;
        if(tval <= 100){
            tval = 100;
        }
        tid = this->startTimer(tval);
    }
}


void Tetris::down(){
        if(candown()){
            curr->down();
        } else {
            landdown();
            clearline();
            if(wall[0][4] != NULL){
                QMessageBox box(QMessageBox::Question,"Quit or Continue","Game Over!!!,Restart?",QMessageBox::No|QMessageBox::Yes);
                if(box.exec() == QMessageBox::No){
                    close();
                }else{
                    killTimer(tid);
                    init();
                }
            }
            newnext();
        }
}

bool Tetris::candown(){
    for (int i=0;i<4;i++) {
        if(curr->cells[i]->row<=0)
            continue;
        if(curr->cells[i]->row>=19)
            return false;
        if(wall[curr->cells[i]->row + 1][curr->cells[i]->col] != NULL)
            return false;
    }
    return true;
}


bool Tetris::canleft(){
        for(int i=0;i<4;i++){
            if(curr->cells[i]->col==0)
                return false;
            if(curr->cells[i]->row<=0)
                continue;
            if(wall[curr->cells[i]->row][curr->cells[i]->col - 1] != NULL)
                return false;
            }return true;
}

bool Tetris::canright(){
    for(int i=0;i<4;i++){
        if(curr->cells[i]->col==9)
            return false;
        if(curr->cells[i]->row<=0)
            continue;
        if(wall[curr->cells[i]->row][curr->cells[i]->col + 1] != NULL)
            return false;
        }
        return true;
}

void Tetris::rotate(){
    curr->rotate(1);
    if(outofbound() || coincidence()){
        curr->rotate(-1);
    }

}

bool Tetris::outofbound(){
    for(int i=0;i<4;i++){
        if(curr->cells[i]->col<0 || curr->cells[i]->col>9){
            return true;
        }if(curr->cells[i]->row>19){
            return true;
        }
        }return false;

}

bool Tetris::coincidence(){
    for(int i=0;i<4;i++){
            if(curr->cells[i]->row<0){
                continue;
            }
        if(wall[curr->cells[i]->row][curr->cells[i]->col] != NULL){
        return true;
        }
    }
    return false;
}

